vulkan: Implement nonseparable blendmodes
authorMatthias Clasen <mclasen@redhat.com>
Sat, 23 Sep 2017 12:59:06 +0000 (08:59 -0400)
committerMatthias Clasen <mclasen@redhat.com>
Sat, 23 Sep 2017 13:16:58 +0000 (09:16 -0400)
This is a directly-from-the-spec, unoptimized implementation.

gsk/gskvulkanrenderpass.c
gsk/resources/vulkan/blendmode-clip-rounded.frag.spv
gsk/resources/vulkan/blendmode-clip.frag.spv
gsk/resources/vulkan/blendmode.frag
gsk/resources/vulkan/blendmode.frag.spv

index 3f9c7aa0c6795b918a4818102680b524889ada19..fe1187243cb178e54b24c8e5ccba2e51e35b4e66 100644 (file)
@@ -186,11 +186,6 @@ gsk_vulkan_render_pass_add_node (GskVulkanRenderPass           *self,
       FALLBACK ("Unsupported node '%s'\n", node->node_class->type_name);
 
     case GSK_BLEND_NODE:
-      if (gsk_blend_node_get_blend_mode (node) == GSK_BLEND_MODE_COLOR ||
-          gsk_blend_node_get_blend_mode (node) == GSK_BLEND_MODE_HUE ||
-          gsk_blend_node_get_blend_mode (node) == GSK_BLEND_MODE_SATURATION ||
-          gsk_blend_node_get_blend_mode (node) == GSK_BLEND_MODE_LUMINOSITY)
-        FALLBACK ("Nonseparable blend modes not implemented\n");
       if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
         pipeline_type = GSK_VULKAN_PIPELINE_BLEND_MODE;
       else if (constants->clip.type == GSK_VULKAN_CLIP_RECT)
index 4ede20eb07cb298a1cded6064e3c32c752b98818..b204175b0f5f5055bed90b8a8bb2f983f6483346 100644 (file)
Binary files a/gsk/resources/vulkan/blendmode-clip-rounded.frag.spv and b/gsk/resources/vulkan/blendmode-clip-rounded.frag.spv differ
index 21484c8e1815cde307698321abe329557fd3c4cb..e3e681df6f58ef9c3ea41fbcc665bf88be83029e 100644 (file)
Binary files a/gsk/resources/vulkan/blendmode-clip.frag.spv and b/gsk/resources/vulkan/blendmode-clip.frag.spv differ
index 803a538d1ddedb084841a2bc4fdbf50a65b4163e..4e448acd5c7ee285d8abcecef6459c0b917496e1 100644 (file)
@@ -10,7 +10,7 @@ layout(location = 3) flat in uint inBlendMode;
 layout(set = 0, binding = 0) uniform sampler2D startTexture;
 layout(set = 1, binding = 0) uniform sampler2D endTexture;
 
-layout(location = 0) out vec4 color;
+layout(location = 0) out vec4 outColor;
 
 vec3
 multiply (vec3 source, vec3 backdrop, float opacity)
@@ -134,6 +134,121 @@ exclusion (vec3 source, vec3 backdrop, float opacity)
   return mix (source, result, opacity);
 }
 
+float
+lum (vec3 c)
+{
+  return 0.3 * c.r + 0.59 * c.g + 0.11 * c.b;
+}
+
+vec3
+clip_color (vec3 c)
+{
+  float l = lum (c);
+  float n = min (c.r, min (c.g, c.b));
+  float x = max (c.r, max (c.g, c.b));
+  if (n < 0) c = l + (((c - l) * l) / (l - n));
+  if (x > 1) c = l + (((c - l) * (1 - l)) / (x - l));
+  return c;
+}
+
+vec3
+set_lum (vec3 c, float l)
+{
+  float d = l - lum (c);
+  return clip_color (vec3 (c.r + d, c.g + d, c.b + d));
+}
+
+float
+sat (vec3 c)
+{
+  return max (c.r, max (c.g, c.b)) - min (c.r, min (c.g, c.b));
+}
+
+vec3
+set_sat (vec3 c, float s)
+{
+  float cmin = min (c.r, min (c.g, c.b));
+  float cmax = max (c.r, max (c.g, c.b));
+  vec3 res;
+
+  if (cmax == cmin)
+    res = vec3 (0, 0, 0);
+  else
+    {
+      if (c.r == cmax)
+        {
+          if (c.g == cmin)
+            {
+              res.b = ((c.b - cmin) * s) / (cmax - cmin);
+              res.g = 0;
+            }
+          else
+            {
+              res.g = ((c.g - cmin) * s) / (cmax - cmin);
+              res.b = 0;
+            }
+          res.r = s;
+        }
+      else if (c.g == cmax)
+        {
+          if (c.r == cmin)
+            {
+              res.b = ((c.b - cmin) * s) / (cmax - cmin);
+              res.r = 0;
+            }
+          else
+            {
+              res.r = ((c.r - cmin) * s) / (cmax - cmin);
+              res.b = 0;
+            }
+          res.g = s;
+        }
+      else
+        {
+          if (c.r == cmin)
+            {
+              res.g = ((c.g - cmin) * s) / (cmax - cmin);
+              res.r = 0;
+            }
+          else
+            {
+              res.r = ((c.r - cmin) * s) / (cmax - cmin);
+              res.g = 0;
+            }
+          res.b = s;
+        }
+    }
+  return res;
+}
+
+vec3
+color (vec3 source, vec3 backdrop, float opacity)
+{
+  vec3 result = set_lum (source, lum (backdrop));
+  return mix (source, result, opacity);
+}
+
+vec3
+hue (vec3 source, vec3 backdrop, float opacity)
+{
+  vec3 result = set_lum (set_sat (source, sat (backdrop)), lum (backdrop));
+  return mix (source, result, opacity);
+}
+
+vec3
+saturation (vec3 source, vec3 backdrop, float opacity)
+{
+  vec3 result = set_lum (set_sat (backdrop, sat (source)), lum (backdrop));
+  return mix (source, result, opacity);
+}
+
+vec3
+luminosity (vec3 source, vec3 backdrop, float opacity)
+{
+  vec3 result = set_lum (backdrop, lum (source));
+  return mix (source, result, opacity);
+}
+
 float
 combine (float source, float backdrop)
 {
@@ -176,8 +291,16 @@ void main()
     rgb = difference (source.rgb, backdrop.rgb, backdrop.a);
   else if (inBlendMode == 11)
     rgb = exclusion (source.rgb, backdrop.rgb, backdrop.a);
+  else if (inBlendMode == 12)
+    rgb = color (source.rgb, backdrop.rgb, backdrop.a);
+  else if (inBlendMode == 13)
+    rgb = hue (source.rgb, backdrop.rgb, backdrop.a);
+  else if (inBlendMode == 14)
+    rgb = saturation (source.rgb, backdrop.rgb, backdrop.a);
+  else if (inBlendMode == 15)
+    rgb = luminosity (source.rgb, backdrop.rgb, backdrop.a);
   else
     discard;
 
-  color = clip (inPos, vec4 (rgb, a));
+  outColor = clip (inPos, vec4 (rgb, a));
 }
index 21484c8e1815cde307698321abe329557fd3c4cb..e3e681df6f58ef9c3ea41fbcc665bf88be83029e 100644 (file)
Binary files a/gsk/resources/vulkan/blendmode.frag.spv and b/gsk/resources/vulkan/blendmode.frag.spv differ